#ifndef __NET_ACCEPTOR__
#define __NET_ACCEPTOR__

#include<iostream>
#include<functional>

#include<unistd.h>
#include<assert.h>
#include<errno.h>

#include"socket.hpp"
#include"channel.hpp"

//监听描述符管理类
class Acceptor
{
public:
    using AcceptCallback=std::function<void(int)>;
public:
    Acceptor(Eventloop* loop,int port)
        :_accept_socket(createserver(port)),_accept_loop(loop),
         _accept_channel(loop,_accept_socket.get_fd()),
         _accept_idle_fd(open("/dev/null",O_RDONLY|O_CLOEXEC))
    {
        _accept_channel.set_callback(std::bind(&Acceptor::handle_read,this),Channel::Read);
    }

    //设置接收时回调函数
    void set_accpet_callback(const AcceptCallback& cb)
    {
        _accept_cb=cb;
    }

    //开始监听，设置listenfd的读监听
    void Listen()
    {
        _accept_channel.set_events(Channel::Be_Read);
    }

    ~Acceptor()
    {
        _accept_socket.Close();
        close(_accept_idle_fd);
    }

private:
    //监听sock的读事件回调
    void handle_read()
    {
        int newfd=_accept_socket.Accept();
        if(newfd<0)
        {
            if(errno==EINTR)
            {
                ERR("accept failed,errrno=EINTR");
            }
            else if(errno==EMFILE)
            {
                //当EMFILE时，代表系统可以打开的fd已满，需要关闭预占的fd，之后接收监听到的fd，再关闭，之后重新打开预先的fd
                WAR("accept failed,errrno=EMFILE , fd is full ,use idle fd");
                close(_accept_idle_fd);
                _accept_idle_fd=accept(_accept_socket.get_fd(),nullptr,nullptr);
                close(_accept_idle_fd);
                _accept_idle_fd=open("/dev/null",O_RDONLY|O_CLOEXEC);
            }
            else if(errno==EAGAIN)
            {
                ERR("accept failed,errrno=EAGAIN");
            }
            else
            {
                ERR("accept failed,errrno=%d, errno str=%s",errno,strerror(errno));
            }
        }
        else
        {
            INF("accept one connection, sockfd is %d",newfd);
            // EventLoop* sub_loop=
            if(_accept_cb)_accept_cb(newfd);
        }
    }

    int createserver(int port)
    {
        bool ret=_accept_socket.create_server("0.0.0.0",port);
        assert(ret);
        return _accept_socket.get_fd();
    }

private:
    int _accept_idle_fd;        //空闲预占fd

    Socket _accept_socket;      //socket操作对象
    Channel _accept_channel;    //channel操作对象
    Eventloop* _accept_loop;    //eventloop操作对象

    AcceptCallback _accept_cb;  //接收时回调函数
};

#endif